package com.nontax.test.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nontax.test.common.domain.StdRespDetailParameter;
import com.nontax.test.common.domain.StdRespParameter;
import com.nontax.test.common.domain.StdRestConst;
import com.nontax.test.common.domain.StdRestParameter;
import com.nontax.test.common.exception.BusinessException;
import com.nontax.test.common.websocket.WebSocketServer;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.util.UUID;

public class StdRestClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(StdRestClient.class);

    private static ObjectMapper mapper = ObjectMapperUtil.getCustomInstance();

    /**
     * 此超时时间设置为 20s
     *
     * @param object
     * @param returnClass
     * @param url
     * @param appId
     * @param appKey
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T callStdInterface(Object object, Class<T> returnClass, String url,
                                         String appId, String appKey,String sid) throws Exception {
        return callStdInterface(object, returnClass, url, appId, appKey, 20,sid);
    }

    /**
     * @param object
     * @param returnClass
     * @param url
     * @param appId
     * @param appKey
     * @param timeout     超时时间，单位：秒
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T callStdInterface(Object object, Class<T> returnClass, String url,
                                         String appId, String appKey, int timeout,String sid) throws Exception {
        HttpClient httpClient = HttpClientBuilder.create().build();
//		CloseableHttpClient httpClient = .setRedirectStrategy(new LaxRedirectStrategy()).build();
//		HttpClient httpClient = HttpClients.custom()
//				.disableAutomaticRetries() //关闭自动处理重定向
//				.setRedirectStrategy(new LaxRedirectStrategy()).build();//利用LaxRedirectStrategy处理POST重定向问题
        if (StringUtils.isBlank(url)) {
            throw new BusinessException("url不能为空!");
        }
        if (StringUtils.isBlank(appId)) {
            throw new BusinessException("appId不能为空!");
        }
        if (StringUtils.isBlank(appKey)) {
            throw new BusinessException("appKey不能为空!");
        }
//		HttpClient httpClient = HttpClientBuilder.create()
//				.setRedirectStrategy(new PostRedirectStrategy()).build();//重写LaxRedirectStrategy处理POST重定向问题
        HttpPost post = new HttpPost(url);

        RequestConfig.Builder requestBuilder = RequestConfig.custom();
        requestBuilder = requestBuilder.setConnectTimeout(timeout*1000);
        requestBuilder = requestBuilder.setSocketTimeout(timeout*1000);
        requestBuilder = requestBuilder.setConnectionRequestTimeout(timeout*1000);
        post.setConfig(requestBuilder.build());

        StdRestParameter stdRestParameter = new StdRestParameter();
        stdRestParameter.setAppid(appId);
        stdRestParameter.setAppkey(appKey);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        mapper.writeValue(outputStream, object);

        stdRestParameter.setData(Base64.encodeBase64String(outputStream.toByteArray()));
        WebSocketServer.sendInfo("标准协议客户端待发送数据为:"+stdRestParameter.getData(),sid);
        LOGGER.info("标准协议客户端待发送数据为:{}", stdRestParameter.getData());

        stdRestParameter.setNoise(UUID.randomUUID().toString().replace("-", ""));
        stdRestParameter.setVersion(StdRestConst.DEFAULT_VERSION);
        //获取签名值
        stdRestParameter.setSign(StdRestSignUtil.sign(stdRestParameter));
        stdRestParameter.setAppkey(null);
        StringEntity entity = new StringEntity(mapper.writeValueAsString(stdRestParameter), "utf-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        post.setEntity(entity);
        HttpResponse httpResponse = httpClient.execute(post);
        String responseString = IOUtils.toString(httpResponse.getEntity().getContent(), Charsets.UTF_8);
        LOGGER.info("标准接口返回:{}", responseString);
        WebSocketServer.sendInfo(responseString,sid);
        if (StringUtils.isBlank(responseString)) {
            LOGGER.error("标准接口返回数据为空!");
            WebSocketServer.sendInfo("标准接口返回数据为空",sid);
            throw new BusinessException("标准接口返回数据为空!");
        }
        //返回参数
        StdRespParameter respParameter = mapper.readValue(responseString, StdRespParameter.class);

        String data = respParameter.getData();
        stdRestParameter.setData(data);

        if (StringUtils.isBlank(respParameter.getSign())) {
            String decodeData = Base64Util.decodeBase64(data);
            WebSocketServer.sendInfo("服务端返回无签名值,解密后data:"+decodeData,sid);
            LOGGER.error("服务端返回无签名值,data:{},解密后data:{}", data, decodeData);
            throw new BusinessException("服务端返回无签名值,data:" + data + ",解密后data:" + decodeData);
        }

        stdRestParameter.setAppkey(appKey);
        stdRestParameter.setNoise(respParameter.getNoise());
        stdRestParameter.setSign(StdRestSignUtil.sign(stdRestParameter));

        if (!stdRestParameter.getSign().equals(respParameter.getSign())) {
            LOGGER.error("接收签名值为:{},根据返回值生成签名值为:{}", respParameter.getSign(), stdRestParameter.getSign());
            WebSocketServer.sendInfo("接收签名值为:"+respParameter.getSign()+",根据返回值生成签名值为:"+stdRestParameter.getSign(),sid);
            throw new BusinessException("签名值校验出错，请确认返回参数是否已经被篡改!");
        }
        data = Base64Util.decodeBase64(data);
        StdRespDetailParameter stdRespDetailParameter = mapper.readValue(data, StdRespDetailParameter.class);
        //成功
        if (StdRestConst.SUCCESS_CODE.equals(stdRespDetailParameter.getResult())) {
            if(StringUtils.isBlank(stdRespDetailParameter.getMessage())){
                LOGGER.info("标准接口操作成功，但是没有返回信息!");
                WebSocketServer.sendInfo("标准接口操作成功，但是没有返回信息!",sid);
                return null;
            }
            String objectJson = Base64Util.decodeBase64(stdRespDetailParameter.getMessage());
            LOGGER.info("标准接口操作成功:{}", objectJson);
            WebSocketServer.sendInfo("标准接口操作成功,返回的数据为:"+objectJson,sid);
            return mapper.readValue(objectJson, returnClass);
        } else {//其余都是失败
            String message = stdRespDetailParameter.getMessage();
            if (StringUtils.isBlank(message)) {
                throw new BusinessException(data);
            }
            WebSocketServer.sendInfo("标准接口操作成功:"+message,sid);
            LOGGER.info("标准接口操作失败:{}", message);
            throw new RuntimeException(Base64Util.decodeBase64(message));
        }
    }
}
